package br.com.felinelayer.client.clientSwing;

import br.com.felinelayer.client.ComponentIDNotFoundException;
import br.com.felinelayer.common.Message;
import br.com.felinelayer.common.Protocol;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JComponent;
import javax.swing.JFrame;

/**
 *
 */
public abstract class ComponentSwing<T extends br.com.felinelayer.client.IComponentClient, V extends java.awt.Component>
        extends br.com.felinelayer.client.ComponentClient<T> implements FocusListener {

    private LabelClient labelAnchorLeft;
    private LabelClient labelAnchorTop;
    private int oldx;
    private int oldy;
    private int oldw;
    private int oldh;

    protected abstract void doInitialize();

    @Override
    public void initialize() {
        doInitialize();
    }

    protected int getDefaultHeight() {
        return HEIGHT_DEFAULT;
    }

    protected int getDefaultWidth() {
        return 100;
    }

    protected final <K extends java.awt.Component> V initializeComponente(K jcomponent) {
        Dimension s = jcomponent.getSize();
        s.height = getDefaultHeight();
        s.width = getDefaultWidth();
        jcomponent.setSize(s);
        setObject(jcomponent);
        return (V) jcomponent;
    }
    public static final int HEIGHT_DEFAULT = 24;
    private Object object;
    private String previosText = "";

    @Override
    public T setVisible(boolean visible) {
        if (getObject() instanceof JComponent) {
            ((JComponent) getObject()).setVisible(visible);
        }
        if (getObject() instanceof JFrame) {
            ((JFrame) getObject()).setVisible(visible);
        }
        return (T) this;
    }

    @Override
    public T setHint(String text) {
        if (getObject() instanceof JComponent) {
            ((JComponent) getObject()).setToolTipText(text);
        }
        return (T) this;
    }

    @Override
    public T setWidht(int width) {
        Dimension d = getDimension();
        d.width = width;
        setDimension(d);
        return (T) this;
    }

    @Override
    public T setHeight(int height) {
        Dimension d = getDimension();
        d.height = height;
        setDimension(d);
        return (T) this;
    }

    @Override
    public abstract T setText(String text);

    @Override
    public abstract String getText();

    @Override
    public Object getObject() {
        return object;
    }

    public T setObject(Object object) {
        this.object = object;
        if (object instanceof JComponent) {
            ((JComponent) getObject()).addFocusListener(this);
        }
        return (T) this;
    }

    public Rectangle getBounds() {
        if (getObject() instanceof JComponent) {
            return ((JComponent) getObject()).getBounds();
        }
        if (getObject() instanceof JFrame) {
            return ((JFrame) getObject()).getBounds();
        }
        return null;
    }

    public T setBounds(Rectangle rectangle) {
        if (getObject() instanceof JComponent) {
            ((JComponent) getObject()).setBounds(rectangle);
            setHint(getDimStr());
            if ((oldx != rectangle.x)
                    || (oldy != rectangle.y)
                    || (oldw != rectangle.width)
                    || (oldh != rectangle.height)) {
                if (labelAnchorLeft != null) {
                    labelAnchorLeft.updateAnchorLeft(this);
                }
                if (labelAnchorTop != null) {
                    labelAnchorTop.updateAnchorTop(this);
                }
            }
            oldx = rectangle.x;
            oldy = rectangle.y;
            oldw = rectangle.width;
            oldh = rectangle.height;
        }
        if (getObject() instanceof JFrame) {
            ((JFrame) getObject()).setBounds(rectangle);
        }
        return (T) this;
    }

    public Dimension getDimension() {
        if (getObject() instanceof JComponent) {
            return ((JComponent) getObject()).getSize();
        }
        if (getObject() instanceof JFrame) {
            return ((JFrame) getObject()).getSize();
        }
        return null;
    }

    public T setDimension(Dimension rectangle) {
        if (getObject() instanceof JComponent) {
            ((JComponent) getObject()).setSize(rectangle);
            setHint(getDimStr());
            if ((oldw != rectangle.width) || (oldh != rectangle.height)) {
                if (labelAnchorLeft != null) {
                    labelAnchorLeft.updateAnchorLeft(this);
                }
                if (labelAnchorTop != null) {
                    labelAnchorTop.updateAnchorTop(this);
                }
            }
            oldw = rectangle.width;
            oldh = rectangle.height;
        }
        if (getObject() instanceof JFrame) {
            ((JFrame) getObject()).setSize(rectangle);
        }
        return (T) this;
    }

    @Override
    public int getHeight() {
        return (int) getBounds().getHeight();
    }

    @Override
    public int getWidth() {
        return (int) getBounds().getWidth();
    }

    @Override
    public T setTop(int top) {
        Rectangle b = getBounds();
        b.y = top;
        setBounds(b);
        return (T) this;
    }

    @Override
    public T setLeft(int left) {
        Rectangle b = getBounds();
        b.x = left;
        setBounds(b);
        return (T) this;
    }

    protected Message createEvent(String name) throws ComponentIDNotFoundException {
        return getClient().createEvent(this, name);
    }

    protected void fireEvent(String name) throws ComponentIDNotFoundException {
        getClient().sendEvent(this, name);
    }

    protected T fireEvent(Message message) {
        getClient().sendMessage(message);
        return (T) this;
    }

    protected Message fireInquireEvent(Message message) {
        return getClient().inquireMessage(message);
    }

    @Override
    protected void doChangeProperty(Message message) {
    }

    @Override
    public void messageReceived(Message message) {
    }

    /**
     * Invoked when a component gains the keyboard focus.
     */
    @Override
    public void focusGained(FocusEvent e) {
        try {
            setHint(getDimStr());
            previosText = getText();
            fireEvent(Protocol.EVENT_FOCUS_ENTER);
        } catch (ComponentIDNotFoundException ex) {
        } catch (Exception ex) {
            Logger.getLogger(ComponentSwing.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Invoked when a component loses the keyboard focus.
     */
    @Override
    public void focusLost(FocusEvent e) {
        try {
            Message m = createEvent(Protocol.EVENT_FOCUS_EXIT);
            String currentText = getText();
            if (!previosText.equalsIgnoreCase(getText())) {
                m.setValueByName(Protocol.PROPERTY_NAME_TEXT, currentText);
            }
            fireEvent(m);
        } catch (ComponentIDNotFoundException ex) {
        } catch (Exception ex) {
            Logger.getLogger(ComponentSwing.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    protected void doDestroy() {
        if (object instanceof JComponent) {
            ((JComponent) getObject()).getParent().remove((JComponent) getObject());
        }
    }

    @Override
    public int getLeft() {
        return (int) getBounds().getX();
    }

    @Override
    public int getTop() {
        return (int) getBounds().getY();
    }

    @Override
    public String getDimStr() {
        return "text:" + getText() + " x,y:" + getLeft() + "," + getTop()
                + " w,h:" + getWidth() + "," + getHeight();

    }

    @Override
    public void setLabelAnchorLeft(LabelClient label) {
        this.labelAnchorLeft = label;
    }

    @Override
    public void setLabelAnchorTop(LabelClient label) {
        this.labelAnchorTop = label;
    }
}
